package com.kinghunt.misp.web.controller.userx;

import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.fastjson.JSON;
import com.kinghunt.misp.common.constant.SystemConstant;
import com.kinghunt.misp.common.dto.userx.UserDTO;
import com.kinghunt.misp.common.dto.userx.UserImportDTO;
import com.kinghunt.misp.common.param.userx.UserLoginParam;
import com.kinghunt.misp.common.param.userx.UserParam;
import com.kinghunt.misp.common.param.userx.UserQueryCondition;
import com.kinghunt.misp.common.param.userx.UserUpdatePasswordParam;
import com.kinghunt.misp.common.utils.TokenUtils;
import com.kinghunt.misp.common.utils.easyExcel.ImportExcelListener;
import com.kinghunt.misp.service.api.userx.AutoLoginService;
import com.kinghunt.misp.service.api.userx.UserReadService;
import com.kinghunt.misp.service.api.userx.UserWriteService;
import com.kinghunt.misp.web.advice.annotation.LoginRequire;
import com.kinghunt.misp.web.context.ApiContext;
import com.kinghunt.misp.web.context.SystemContext;
import com.bygoodtech.kings.common.dto.ApiResult;
import com.bygoodtech.kings.common.dto.page.PageInfo;
import com.bygoodtech.kings.common.utils.Checker;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;


/**
 * 用户管理
 *
 * @Author jiangtao
 * @Date 2023/7/4 18:46
 */
@Slf4j
@RestController
@RequestMapping("/api/userx/user/")
public class UserController {
    private final UserReadService userReadService;
    private final UserWriteService userWriteService;
    private final AutoLoginService autoLoginService;

    public UserController(UserReadService userReadService,
                          UserWriteService userWriteService,
                          AutoLoginService autoLoginService) {
        this.userReadService = userReadService;
        this.userWriteService = userWriteService;
        this.autoLoginService = autoLoginService;
    }

    /**
     * 查询单个用户信息
     */
    @GetMapping("getUserById")
    public ApiResult<UserDTO> getUserById(Long id) {
        return userReadService.getUserById(id);
    }

    /**
     * 批量查询用户信息
     */
    @GetMapping("getUsersByIds")
    public ApiResult<List<UserDTO>> getUsersByIds(List<Long> ids) {
        return userReadService.getUsersByIds(ids);
    }

    /**
     * 获取当前登录用户
     *
     * @return
     */
    @GetMapping("getCurrentUser")
    public ApiResult<UserDTO> getCurrentUser(HttpServletRequest request) {
        Long userId = ApiContext.apiUser().getUserId();
        UserDTO user;
        if (Objects.isNull(userId) || 0 == userId) {
            user = Checker.success(autoLoginService.loginByIp(request));
            if (Objects.nonNull(user)) {
                user.setToken(TokenUtils.toToken(user.getId()));
            }
        } else {
            user = Checker.success(userReadService.getUserById(userId));
        }
        return ApiResult.ok(user);
    }

    /**
     * 查询机构下所有用户信息
     */
    @GetMapping("getUsersByOrganizationId")
    public ApiResult<List<UserDTO>> getUsersByOrganizationId(long organizationId) {
        return userReadService.getUsersByOrganizationId(organizationId);
    }

    /**
     * 根据查询条件分页搜索用户
     * 如果是机构管理员，则只能搜索自己所在机构的用户；如果是超级管理员或系统管理员，则可以搜索所有用户
     *
     * @param condition 查询条件
     * @return 分页结果
     */
    @GetMapping("searchUsers")
    public ApiResult<PageInfo<UserDTO>> searchUsers(UserQueryCondition condition) {
        // 如果是机构管理员，则只能搜索自己所在机构的用户；如果是超级管理员或系统管理员，则可以搜索所有用户
        UserDTO loginUser = SystemContext.getCurrentUser();
        if (Objects.isNull(loginUser)) {
            return ApiResult.failOfMessage("请登录后重试");
        }
        // 角色为机构管理员，则只能搜索本机构用户
        if (loginUser.getRoleId().equals(3L)) {
            condition.setOrganizationId(loginUser.getOrganizationId());
        }
        return userReadService.searchUsers(condition);
    }

    /**
     * 新增用户
     */
    @PostMapping(value = "addUser", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ApiResult<Long> addUser(@RequestBody UserParam userParam) {
        if (StringUtils.isEmpty(userParam.getAppCode())) {
            userParam.setAppCode(SystemConstant.SYSTEM_CODE);
        }

        if (StringUtils.isEmpty(userParam.getPassword())) {
            // 默认用户密码
            userParam.setPassword(SystemConstant.DEFAULT_USER_PASSWORD);
        }
        return userWriteService.addUser(userParam);
    }

    @GetMapping(value = "addUserTest")
    public ApiResult<Long> addUserTest() {
        UserParam userParam = new UserParam();
        userParam.setOrganizationId(2l);
        userParam.setOrganizationName("万博");
        userParam.setUsername("测试数据");
        userParam.setNickname("风");
        userParam.setPassword("123456");
        userParam.setAppCode(SystemConstant.SYSTEM_CODE);
        return userWriteService.addUser(userParam);
    }

    /**
     * excel批量导入用户
     */
    @PostMapping(value = "importUser", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ApiResult<Void> importUser(@RequestParam MultipartFile file) {
        UserDTO loginUser = SystemContext.getCurrentUser();

        List<String> errorList = new ArrayList<>();
        List<UserImportDTO> userImportDTOs = new ArrayList<>();
        try (ExcelReader excelReader = EasyExcelFactory.read(file.getInputStream()).build()) {
            ReadSheet dealerSheet = EasyExcelFactory
                    .readSheet(0)
                    .head(UserImportDTO.class)
                    .registerReadListener(new ImportExcelListener<UserImportDTO>(data -> {
                        for (UserImportDTO user : data) {
                            if(StringUtils.isEmpty(user.getUsername()) || null == user.getRoleId()){
                                errorList.add(String.format("第%d行解析异常:用户名或角色为空", user.getRowIndex()));
                            }else{
                                userImportDTOs.add(user);
                            }
                        }
                        log.info("订单信息数据：" + JSON.toJSONString(data));
                    }, errorList))
                    .build();
            excelReader.read(dealerSheet);
        } catch (IOException e) {
            log.error("处理excel失败，" + e.getMessage());
        }

        return userWriteService.importUser(loginUser, userImportDTOs, errorList);
    }

    /**
     * 系统批量生成用户
     */
    @GetMapping("autogenerateUser")
    public ApiResult<Long> autogenerateUser() {
        // TODO:
        return ApiResult.ok();
    }

    /**
     * 更新用户信息
     */
    @PostMapping(value = "updateUserInfo", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ApiResult updateUserInfo(@RequestBody UserParam userParam) {
        return userWriteService.updateUserInfo(userParam);
    }

    /**
     * 更新用户信息
     */
    @PostMapping(value = "updateSelfInfo", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ApiResult updateSelfInfo(@RequestBody UserParam userParam) {
        Long userId = ApiContext.apiUser().getUserId();
        userParam.setId(userId);
        return userWriteService.updateUserInfo(userParam);
    }

    /**
     * 修改密码
     */
    @PostMapping(value = "updatePassword", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    //@RequiresPermissions("sys:user:password")
    public ApiResult updatePassword(UserUpdatePasswordParam param) {
        Long userId = param.getUserId();
        Long operatorId = ApiContext.apiUser().getUserId();
        log.info("updatePassword {} - {} - {} - {}", userId, param.getOldPassword(), param.getNewPassword(), operatorId);
        Checker.success(userWriteService.updatePassword(userId, param.getOldPassword(), param.getNewPassword()));
        return ApiResult.ok();
    }

    /**
     * 修改密码
     */
    @PostMapping(value = "updateSelfPassword", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    //@RequiresPermissions("sys:user:password")
    public ApiResult updateSelfPassword(UserUpdatePasswordParam param) {
        Long userId = ApiContext.apiUser().getUserId();
        log.info("updateSelfPassword {} - {} - {}", userId, param.getOldPassword(), param.getNewPassword());
        Checker.success(userWriteService.updatePassword(userId, param.getOldPassword(), param.getNewPassword()));
        return ApiResult.ok();
    }

    /**
     * 重置密码
     *
     * @param userId 待重置密码的用户ID
     * @return
     */
    @GetMapping("resetPassword")
    public ApiResult resetPassword(Long userId) {
        UserDTO loginUser = SystemContext.getCurrentUser();
        return userWriteService.resetPassword(loginUser, userId);
    }

    @PostMapping("sign-in")
    public ApiResult<Void> signIn(@RequestBody UserParam user) {
        Assert.isTrue(StringUtils.hasText(user.getUsername()), "invalid userName");
        Assert.isTrue(StringUtils.hasText(user.getPhone()), "invalid phone");
        Assert.isTrue(StringUtils.hasText(user.getVerifyCode()), "invalid verify code");

        return this.userWriteService.registerUser(user);
    }

    @PostMapping("update-user-name")
    @LoginRequire
    public ApiResult<Void> updateUserName(@RequestBody Map<String, String> body) {
        String userName = body.get("userName");
        Assert.isTrue(StringUtils.hasText(userName), "invalid userName");
        return this.userWriteService.updateUserName(ApiContext.apiUser().getUserId(), userName);
    }

    @PostMapping("login-with-username")
    public ApiResult<String> loginWithUserName(@RequestBody UserParam user) {
        Assert.isTrue(StringUtils.hasText(user.getUsername()), "invalid userName or mobilePhone");
        Assert.isTrue(StringUtils.hasText(user.getPassword()), "invalid password");

        return this.userReadService.loginWithNameAndPassword(user.getUsername(), user.getPassword());
    }

    /**
     * 登录
     *
     * @param param 机构ID，用户名，密码
     * @return token
     */
    @PostMapping(value = "login", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ApiResult<String> login(@RequestBody UserLoginParam param) {
        if (Objects.isNull(param) || Objects.isNull(param.getOrgId())
                || org.apache.commons.lang3.StringUtils.isBlank(param.getUsername())
                || org.apache.commons.lang3.StringUtils.isBlank(param.getPassword())) {
            return ApiResult.failOfMessage("登录失败");
        }

        String token = Checker.success(userReadService.login(param));
        return ApiResult.ok(token);
    }

    @GetMapping("loginTest")
    public ApiResult<String> loginTest(UserLoginParam param) {
        if (Objects.isNull(param) || Objects.isNull(param.getOrgId())
                || org.apache.commons.lang3.StringUtils.isBlank(param.getUsername())
                || org.apache.commons.lang3.StringUtils.isBlank(param.getPassword())) {
            return ApiResult.failOfMessage("登录失败");
        }

        String token = Checker.success(userReadService.login(param));
        return ApiResult.ok(token);
    }
}
